package com.wiscamp.ninechapters.problems.application.assemblers;

import com.wiscamp.ninechapters.common.core.ParseHelper;
import com.wiscamp.ninechapters.problems.application.dto.commands.problems.*;
import com.wiscamp.ninechapters.problems.domain.models.problems.answers.*;
import com.wiscamp.ninechapters.problems.domain.models.problems.problems.CompositeProblem;
import com.wiscamp.ninechapters.problems.domain.models.problems.problems.HybridProblem;
import com.wiscamp.ninechapters.problems.domain.models.problems.problems.SimpleProblem;
import com.wiscamp.ninechapters.problems.domain.models.problems.problems.Stem;
import com.wiscamp.ninechapters.problems.domain.models.problems.problems.composite.*;
import com.wiscamp.ninechapters.problems.domain.models.problems.problems.simple.*;
import com.wiscamp.ninechapters.problems.domain.models.problems.questions.*;
import com.wiscamp.ninechapters.problems.domain.models.types.ProblemType;
import com.wiscamp.ninechapters.problems.domain.models.types.QuestionType;
import com.wiscamp.ninechapters.problems.domain.repositories.ProblemRepository;
import com.wiscamp.ninechapters.problems.domain.repositories.ProblemTypeRepository;
import com.wiscamp.ninechapters.problems.domain.repositories.QuestionTypeRepository;
import com.wiscamp.ninechapters.problems.enums.*;
import com.wiscamp.ninechapters.problems.math.*;
import cube.common.core.CollectionUtils;
import jakarta.validation.constraints.NotNull;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
public class ProblemCommandConverter {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final ProblemRepository problemRepository;

    private final ProblemTypeRepository problemTypeRepository;

    private final QuestionTypeRepository questionTypeRepository;

    public ProblemCommandConverter(ProblemRepository problemRepository, ProblemTypeRepository problemTypeRepository, QuestionTypeRepository questionTypeRepository) {
        this.problemRepository = problemRepository;
        this.problemTypeRepository = problemTypeRepository;
        this.questionTypeRepository = questionTypeRepository;
    }


    // region command converter
    public ProblemModes getProblemMode(long problemId) {
        var problem = problemRepository.getProblem(problemId);
        if (Objects.isNull(problem)) return null;
        if (Objects.isNull(problem.getProblemType())) return null;
        return problem.getProblemType().getProblemMode();
    }

    private Question findQuestion(Collection<Question> questions, long questionId) {
        for (var question : questions) {
            if (question.getQuestionId() == questionId)
                return question;
        }
        return null;
    }

    public CreateSimpleProblemCommand covertCreateSimpleProblemCommand(@NotNull CreateProblemCommand command) {
        if (command.getProblemMode() != ProblemModes.SIMPLE) return null;

        var createSimpleProblemCommand = ProblemAssembler.Instance.toCreateSimpleProblemCommand(command);
        var questions = command.getQuestions();
        var createQuestionDto = (CreateQuestionDto) questions.toArray()[0];
        createSimpleProblemCommand.setQuestion(createQuestionDto);
        createSimpleProblemCommand.setQuestionTypeId(createQuestionDto.getQuestionTypeId());
        return createSimpleProblemCommand;
    }

    public UpdateSimpleProblemCommand covertUpdateSimpleProblemCommand(UpdateProblemCommand command) {
        var mode = getProblemMode(command.getProblemId());
        if (mode != ProblemModes.SIMPLE) return null;

        var updateSimpleProblemCommand = ProblemAssembler.Instance.toUpdateSimpleProblemCommand(command);
        var questions = command.getQuestions();
        var updateQuestionDto = (UpdateQuestionDto) questions.toArray()[0];
        updateSimpleProblemCommand.setQuestion(updateQuestionDto);
        return updateSimpleProblemCommand;
    }

    public CreateCompositeProblemCommand covertCreateCompositeProblemCommand(CreateProblemCommand command) {
        if (command.getProblemMode() != ProblemModes.COMPOSITE) return null;

        var createCompositeProblemCommand = ProblemAssembler.Instance.toCreateCompositeProblemCommand(command);
        var questions = command.getQuestions();
        var createQuestionDto = (CreateQuestionDto) questions.toArray()[0];
        createCompositeProblemCommand.setQuestionTypeId(createQuestionDto.getQuestionTypeId());
        return createCompositeProblemCommand;
    }

    public UpdateCompositeProblemCommand covertUpdateCompositeProblemCommand(UpdateProblemCommand command) {
        var mode = getProblemMode(command.getProblemId());
        if (mode != ProblemModes.SIMPLE) return null;

        var updateCompositeProblemCommand = ProblemAssembler.Instance.toUpdateCompositeProblemCommand(command);
        var questions = command.getQuestions();
        return updateCompositeProblemCommand;
    }

    public CreateHybridProblemCommand covertCreateHybridProblemCommand(CreateProblemCommand command) {
        if (command.getProblemMode() != ProblemModes.HYBRID) return null;
        var createHybridProblemCommand = ProblemAssembler.Instance.toCreateHybridProblemCommand(command);
        return createHybridProblemCommand;
    }

    public UpdateHybridProblemCommand covertUpdateHybridProblemCommand(UpdateProblemCommand command) {
        var mode = getProblemMode(command.getProblemId());
        if (mode != ProblemModes.SIMPLE) return null;

        var updateHybridProblemCommand = ProblemAssembler.Instance.toUpdateHybridProblemCommand(command);
        return updateHybridProblemCommand;
    }

    // endregion

    // region simple problem

    public SimpleProblem buildSimpleProblemByCreateCommand(CreateSimpleProblemCommand command) {
        var problemType = problemTypeRepository.getProblemType(command.getProblemTypeId());
        var questionType = questionTypeRepository.getQuestionType(command.getQuestionTypeId());
        if (Objects.isNull(problemType) || Objects.isNull(questionType)) {
            logger.error("Failed to get type information: {} / {}", command.getProblemTypeId(), command.getQuestionTypeId());
            return null;
        }

        var commonQuestionMode = problemType.getCommonQuestionMode();
        var questionDto = command.getQuestion();
        var question = createByQuestionDto(commonQuestionMode, questionDto, problemType, questionType);

        SimpleProblem simpleProblem = null;
        switch (commonQuestionMode) {
            case TRUE_FALSE:
                simpleProblem = new TrueFalseProblem();
                ((TrueFalseProblem) simpleProblem).setQuestion((TrueFalseQuestion) question);
                break;
            case MULTIPLE_CHOICE:
                simpleProblem = new MultipleChoiceProblem();
                ((MultipleChoiceProblem) simpleProblem).setQuestion((MultipleChoiceQuestion) question);
                break;
            case MULTIPLE_SELECTION:
                simpleProblem = new MultipleSelectionProblem();
                ((MultipleSelectionProblem) simpleProblem).setQuestion((MultipleSelectionQuestion) question);
                break;
            case CALCULATION:
                simpleProblem = new CalculationProblem();
                ((CalculationProblem) simpleProblem).setQuestion((CalculationQuestion) question);
                break;
            case COMPLETION:
                simpleProblem = new CompletionProblem();
                ((CompletionProblem) simpleProblem).setQuestion((CompletionQuestion) question);
                break;
            case GEOMETRY_CALCULATION:
                simpleProblem = new GeometryCalculationProblem();
                ((GeometryCalculationProblem) simpleProblem).setQuestion((GeometryCalculationQuestion) question);
                break;
            case GEOMETRY_COMPLETION:
                simpleProblem = new GeometryCompletionProblem();
                ((GeometryCompletionProblem) simpleProblem).setQuestion((GeometryCompletionQuestion) question);
                break;
            case COLUMN_CALCULATION:
                simpleProblem = new ColumnCalculationProblem();
                ((ColumnCalculationProblem) simpleProblem).setQuestion((ColumnCalculationQuestion) question);
                break;
            case FORMULA_SOLVE:
                simpleProblem = new EquationInequalityProblem();
                ((EquationInequalityProblem) simpleProblem).setQuestion((EquationInequalityQuestion) question);
                break;
            case WORD:
                simpleProblem = new WordProblem();
                ((WordProblem) simpleProblem).setQuestion((WordQuestion) question);
                break;
            case FACTORS_MULTIPLES:
                simpleProblem = new FactorsMultiplesProblem();
                ((FactorsMultiplesProblem) simpleProblem).setQuestion((FactorsMultiplesQuestion) question);
                break;
            case PROBABILITY:
                simpleProblem = new ProbabilityProblem();
                ((ProbabilityProblem) simpleProblem).setQuestion((ProbabilityCalculationQuestion) question);
                break;
            case PROVE:
                simpleProblem = new ProveProblem();
                ((ProveProblem) simpleProblem).setQuestion((ProveQuestion) question);
                break;
            case RATIO_PROPORTION:
                simpleProblem = new RatioProportionProblem();
                ((RatioProportionProblem) simpleProblem).setQuestion((RatioProportionQuestion) question);
                break;
            case STATISTICS:
                simpleProblem = new StatisticsProblem();
                ((StatisticsProblem) simpleProblem).setQuestion((StatisticsCalculationQuestion) question);
                break;
            case UNIT_CONVERSION:
                simpleProblem = new UnitConversionProblem();
                ((UnitConversionProblem) simpleProblem).setQuestion((UnitConversionQuestion) question);
                break;
            case SHORT_ANSWER:
                simpleProblem = new ShortAnswerProblem();
                ((ShortAnswerProblem) simpleProblem).setQuestion((ShortAnswerQuestion) question);
                break;
            default:
                logger.error("Failed to create simple problem.");
        }

        simpleProblem.setCollectionId(command.getCollectionId());
        simpleProblem.setProblemType(problemType);
        simpleProblem.setProblemTypeId(problemType.getTypeId());
        simpleProblem.setCreatorId(command.getOperatorId());
        simpleProblem.setTimeLimit(command.getTimeLimit());
        simpleProblem.setEnabled(command.isEnabled());
        simpleProblem.setCreationTime(LocalDateTime.now());
        simpleProblem.setModifierId(command.getOperatorId());
        simpleProblem.setModificationTime(LocalDateTime.now());
        simpleProblem.setRemark(command.getRemark());
        return simpleProblem;
    }

    public SimpleProblem buildSimpleProblemByUpdateCommand(UpdateSimpleProblemCommand command) {
        // 加载 Problem
        var problem = problemRepository.getProblem(command.getProblemId());
        if (Objects.isNull(problem)) {
            logger.error("Failed to find the problem: {}", command.getProblemId());
            return null;
        }

        var problemType = problem.getProblemType();
        // 更新题属性
        problem.setTimeLimit(command.getTimeLimit());
        problem.setRemark(command.getRemark());
        problem.setEnabled(command.isActive());
        problem.setModifierId(command.getOperatorId());
        problem.setModificationTime(LocalDateTime.now());
        problem.setRemark(command.getRemark());
        var question = problem.getCurrentQuestion();
        var questionDto = command.getQuestion();
        if (Objects.nonNull(question) && Objects.nonNull(questionDto)) {
            updateByUpdateQuestionDto(questionDto, question);
        } else {
            logger.error("The instance of question or question dto is null.");
            return null;
        }
        return (SimpleProblem) problem;
    }
    // endregion

    // region composite problem
    public CompositeProblem buildCompositeProblemByCreateCommand(CreateCompositeProblemCommand command) {
        var problemType = problemTypeRepository.getProblemType(command.getProblemTypeId());
        var questionType = questionTypeRepository.getQuestionType(command.getQuestionTypeId());
        var questionDtoList = command.getQuestions();
        if (Objects.isNull(problemType) || Objects.isNull(questionType)) {
            logger.error("Failed to get type information: {} / {}", command.getProblemTypeId(), command.getQuestionTypeId());
            return null;
        }

        CompositeProblem compositeProblem = null;
        CommonQuestionModes commonQuestionMode = problemType.getCommonQuestionMode();

        var questions = new ArrayList<Question>();
        for (var questionDto : questionDtoList) {
            var question = createByQuestionDto(commonQuestionMode, questionDto, problemType, questionType);
            questions.add(question);
        }

        switch (commonQuestionMode) {
            case TRUE_FALSE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeTrueFalseProblem();
                for (var question : questions)
                    ((CompositeTrueFalseProblem) compositeProblem).getQuestions().add((TrueFalseQuestion) question);
                break;
            case MULTIPLE_CHOICE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeMultipleChoiceProblem();
                for (var question : questions)
                    ((CompositeMultipleChoiceProblem) compositeProblem).getQuestions().add((MultipleChoiceQuestion) question);
                break;
            case MULTIPLE_SELECTION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeMultipleSelectionProblem();
                for (var question : questions)
                    ((CompositeMultipleSelectionProblem) compositeProblem).getQuestions().add((MultipleSelectionQuestion) question);
                break;
            case CALCULATION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeCalculationProblem();
                for (var question : questions)
                    ((CompositeCalculationProblem) compositeProblem).getQuestions().add((CalculationQuestion) question);
                break;
            case COMPLETION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeCompletionProblem();
                for (var question : questions)
                    ((CompositeCompletionProblem) compositeProblem).getQuestions().add((CompletionQuestion) question);
                break;
            case GEOMETRY_CALCULATION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeGeometryCalculationProblem();
                for (var question : questions)
                    ((CompositeGeometryCalculationProblem) compositeProblem).getQuestions().add((GeometryCalculationQuestion) question);
                break;
            case GEOMETRY_COMPLETION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeGeometryCompletionProblem();
                for (var question : questions)
                    ((CompositeGeometryCompletionProblem) compositeProblem).getQuestions().add((GeometryCompletionQuestion) question);
                break;
            case COLUMN_CALCULATION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeColumnCalculationProblem();
                for (var question : questions)
                    ((CompositeColumnCalculationProblem) compositeProblem).getQuestions().add((ColumnCalculationQuestion) question);
                break;
            case FORMULA_SOLVE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeEquationInequalityProblem();
                for (var question : questions)
                    ((CompositeEquationInequalityProblem) compositeProblem).getQuestions().add((EquationInequalityQuestion) question);
                break;
            case WORD:
                if (compositeProblem == null)
                    compositeProblem = new CompositeWordProblem();
                for (var question : questions)
                    ((CompositeWordProblem) compositeProblem).getQuestions().add((WordQuestion) question);
                break;
            case FACTORS_MULTIPLES:
                if (compositeProblem == null)
                    compositeProblem = new CompositeFactorsMultiplesProblem();
                for (var question : questions)
                    ((CompositeFactorsMultiplesProblem) compositeProblem).getQuestions().add((FactorsMultiplesQuestion) question);
                break;
            case PROBABILITY:
                if (compositeProblem == null)
                    compositeProblem = new CompositeProbabilityProblem();
                for (var question : questions)
                    ((CompositeProbabilityProblem) compositeProblem).getQuestions().add((ProbabilityCalculationQuestion) question);
                break;
            case PROVE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeProveProblem();
                for (var question : questions)
                    ((CompositeProveProblem) compositeProblem).getQuestions().add((ProveQuestion) question);
                break;
            case RATIO_PROPORTION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeRatioProportionProblem();
                for (var question : questions)
                    ((CompositeRatioProportionProblem) compositeProblem).getQuestions().add((RatioProportionQuestion) question);
                break;
            case STATISTICS:
                if (compositeProblem == null)
                    compositeProblem = new CompositeStatisticsProblem();
                for (var question : questions)
                    ((CompositeStatisticsProblem) compositeProblem).getQuestions().add((StatisticsCalculationQuestion) question);
                break;
            case UNIT_CONVERSION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeUnitConversionProblem();
                for (var question : questions)
                    ((CompositeUnitConversionProblem) compositeProblem).getQuestions().add((UnitConversionQuestion) question);
                break;
            case SHORT_ANSWER:
                if (compositeProblem == null)
                    compositeProblem = new CompositeShortAnswerProblem();
                for (var question : questions)
                    ((CompositeShortAnswerProblem) compositeProblem).getQuestions().add((ShortAnswerQuestion) question);
                break;
            default:
                logger.error("Failed to create simple problem.");
        }

        var stem = new Stem();
        if (command.getStem() != null) {
            stem.setStemHypertext(command.getStem().getStemHypertext());
            stem.setAction(Actions.CREATE);
        } else {
            stem.setStemHypertext("");
            stem.setAction(Actions.CREATE);
        }

        compositeProblem.setHasStem(problemType.isHasStem());
        compositeProblem.setStem(stem);
        compositeProblem.setCollectionId(command.getCollectionId());
        compositeProblem.setProblemType(problemType);
        compositeProblem.setProblemTypeId(problemType.getTypeId());
        compositeProblem.setCreatorId(command.getOperatorId());
        compositeProblem.setTimeLimit(command.getTimeLimit());
        compositeProblem.setEnabled(command.isEnabled());
        compositeProblem.setCreationTime(LocalDateTime.now());
        compositeProblem.setModifierId(command.getOperatorId());
        compositeProblem.setModificationTime(LocalDateTime.now());
        compositeProblem.setRemark(command.getRemark());
        return compositeProblem;
    }

    public CompositeProblem buildCompositeProblemByUpdateCommand(UpdateCompositeProblemCommand command) {
        // 从数据库加载 Problem
        var problem = problemRepository.getProblem(command.getProblemId());
        if (Objects.isNull(problem)) {
            logger.error("Failed to find the problem: {}", command.getProblemId());
            return null;
        }

        var stem = new Stem();
        if (command.getStem() != null) {
            var stemDto = command.getStem();
            stem.setStemId(stemDto.getStemId());
            stem.setProblemId(problem.getProblemId());
            stem.setStemHypertext(stemDto.getStemHypertext());
            stem.setAction(Actions.UPDATE);
            ((CompositeProblem)problem).setStem(stem);
        }

        //var problemType = typesService.getProblemTypeById(problem.getProblemTypeId());
        var problemType = problem.getProblemType();
        var firstQuestion = (Question) problem.getCurrentQuestions().toArray()[0];
        var questionType = questionTypeRepository.getQuestionType(firstQuestion.getQuestionTypeId());
        if (Objects.isNull(problemType) || Objects.isNull(questionType)) {
            logger.error("Failed to get type information: {} / {}", problem.getProblemType(), firstQuestion.getQuestionTypeId());
            return null;
        }
        var commonQuestionMode = problemType.getCommonQuestionMode();

        // 更新题属性
        problem.setTimeLimit(command.getTimeLimit());
        problem.setRemark(command.getRemark());
        problem.setEnabled(command.isEnabled());
        problem.setModifierId(command.getOperatorId());
        problem.setModificationTime(LocalDateTime.now());

        var questions = problem.getCurrentQuestions();
        var questionDtoAction = Actions.NONE;
        for (var questionDto : command.getQuestions()) {
            questionDtoAction = questionDto.getAction();
            if (questionDtoAction == Actions.DELETE) {
                // 删除question
                var question = findQuestion(problem.getCurrentQuestions(), questionDto.getQuestionId());
                deleteByUpdateQuestionDto(questionDto, question);
                problem.getCurrentQuestions().add(question);
            } else if (questionDtoAction == Actions.CREATE) {
                // 新增question
                var question = createByUpdateQuestionDto(commonQuestionMode, (CompositeProblem) problem, problemType, questionType, questionDto);
                problem.getCurrentQuestions().add(question);
            } else if (questionDtoAction == Actions.UPDATE) {
                // 修改question
                var question = findQuestion(questions, questionDto.getQuestionId());
                updateByUpdateQuestionDto(questionDto, question);
            }
        }
        return (CompositeProblem) problem;
    }
    // endregion

    // region hybrid problem

    public HybridProblem buildHybridProblemByCreateCommand(CreateHybridProblemCommand command) {
        var problemType = problemTypeRepository.getProblemTypeByCode("HYBRID");
        var questionDtoList = command.getQuestions();
        var hybridProblem = new HybridProblem();

        var questions = new ArrayList<Question>();
        for (var questionDto : questionDtoList) {
            var question = createByHybridQuestionDto(questionDto, problemType);
            questions.add(question);
        }

        hybridProblem.setQuestions(questions);

        var stem = new Stem();
        if (command.getStem() != null) {
            stem.setStemHypertext(command.getStem().getStemHypertext());
            stem.setAction(Actions.CREATE);
        } else {
            stem.setStemHypertext("");
            stem.setAction(Actions.CREATE);
        }

        hybridProblem.setStem(stem);
        hybridProblem.setCollectionId(command.getCollectionId());
        hybridProblem.setProblemType(problemType);
        hybridProblem.setProblemTypeId(problemType.getTypeId());
        hybridProblem.setCreatorId(command.getOperatorId());
        hybridProblem.setTimeLimit(command.getTimeLimit());
        hybridProblem.setEnabled(command.isEnabled());
        hybridProblem.setCreationTime(LocalDateTime.now());
        hybridProblem.setModifierId(command.getOperatorId());
        hybridProblem.setModificationTime(LocalDateTime.now());
        hybridProblem.setRemark(command.getRemark());
        return hybridProblem;
    }

    public HybridProblem buildHybridProblemByUpdateCommand(UpdateHybridProblemCommand command) {
        // 从数据库加载 Problem
        var problem = problemRepository.getProblem(command.getProblemId());
        if (Objects.isNull(problem)) {
            logger.error("Failed to find the problem: {}", command.getProblemId());
            return null;
        }

        var stem = new Stem();
        if (command.getStem() != null) {
            var stemDto = command.getStem();
            stem.setStemId(stemDto.getStemId());
            stem.setProblemId(problem.getProblemId());
            stem.setStemHypertext(stemDto.getStemHypertext());
            stem.setAction(Actions.UPDATE);
            ((HybridProblem)problem).setStem(stem);
        }

        var problemType = problemTypeRepository.getProblemType(problem.getProblemTypeId());
        //var firstQuestion = (Question)problem.getCurrentQuestions().toArray()[0];
        //var questionType = typesService.getQuestionTypeById(firstQuestion.getQuestionTypeId());
        /*if (Objects.isNull(problemType) || Objects.isNull(questionType)) {
            logger.error("Failed to get type information: {} / {}", problem.getProblemType(), firstQuestion.getQuestionTypeId());
            return null;
        }*/
        //var commonQuestionMode = problemType.getCommonQuestionMode();

        // 更新题属性
        problem.setTimeLimit(command.getTimeLimit());
        problem.setRemark(command.getRemark());
        problem.setEnabled(command.isActive());
        problem.setModifierId(command.getOperatorId());
        problem.setModificationTime(LocalDateTime.now());

        var questions = problem.getCurrentQuestions();
        var questionDtoAction = Actions.NONE;
        for (var questionDto : command.getQuestions()) {
            questionDtoAction = questionDto.getAction();
            if (questionDtoAction == Actions.DELETE) {
                // 删除question
                var question = findQuestion(problem.getCurrentQuestions(), questionDto.getQuestionId());
                deleteByUpdateQuestionDto(questionDto, question);
                problem.getCurrentQuestions().add(question);
            } else if (questionDtoAction == Actions.CREATE) {
                // 新增question
                var question = createByHybridUpdateQuestionDto(questionDto, problemType);
                problem.getCurrentQuestions().add(question);
            } else if (questionDtoAction == Actions.UPDATE) {
                // 修改question
                var question = findQuestion(questions, questionDto.getQuestionId());
                updateByUpdateQuestionDto(questionDto, question);
            }
        }
        return (HybridProblem) problem;
    }
    // endregion

    // region question dto
    private Question createByQuestionDto(CommonQuestionModes commonQuestionMode, CreateQuestionDto questionDto, ProblemType problemType, QuestionType questionType) {
        Question question = null;

        // pre process solutions
        var solutions = new ArrayList<Solution>();
        solutions.addAll(createBySolutionDtoList(questionDto.getSolutions()));
        Solution preferredSolution = null;
        for (var solution : solutions) {
            if (solution.isPreferred())
                preferredSolution = solution;
        }

        // 如果 questionDto hasOptions == true, 则无需传递answers
        Collection<Answer> correctAnswers = new ArrayList<>();
        Answer correctAnswer = null;
        var options = new ArrayList<Option>();
        if (questionDto.getOptions().size() > 0) {
            // 如果CreateSimpleCommand中包含了Options，则从选项中获取正确答案，忽略Command中的Answers
            // pre process options
            options.addAll(createByOptionDtoList(questionDto.getOptions()));
        } else {
            // pre process answers
            correctAnswers.addAll(createByAnswerDtoList(questionDto.getAnswers()));
            if (correctAnswers.size() == 1)
                correctAnswer = (Answer) correctAnswers.toArray()[0];
        }

        //var options = createByOptionDtoList(questionDto.getOptions());
        //var solutions = createBySolutionDtoList(questionDto.getSolutions());
        //var correctAnswers = createByAnswerDtoList(questionDto.getAnswers());
        //Answer correctAnswer = null;
        //if (correctAnswers.size() == 1)
        //    correctAnswer = (Answer) correctAnswers.toArray()[0];

        switch (commonQuestionMode) {
            case TRUE_FALSE:
                question = new TrueFalseQuestion();
                ((TrueFalseQuestion) question).setAnswer((BooleanAnswer) correctAnswer);
                break;
            case MULTIPLE_CHOICE:
                question = new MultipleChoiceQuestion();
                ((MultipleChoiceQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case MULTIPLE_SELECTION:
                question = new MultipleSelectionQuestion();
                ((MultipleSelectionQuestion) question).setOptions(options);
                ((MultipleSelectionQuestion) question).setAnswer(null);
                break;
            case CALCULATION:
                question = new CalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case COMPLETION:
                question = new CompletionQuestion();
                ((CompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case GEOMETRY_CALCULATION:
                question = new GeometryCalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case GEOMETRY_COMPLETION:
                question = new GeometryCompletionQuestion();
                ((GeometryCompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case COLUMN_CALCULATION:
                question = new ColumnCalculationQuestion();
                ((ColumnCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case FORMULA_SOLVE:
                question = new EquationInequalityQuestion();
                ((EquationInequalityQuestion) question).setAnswers(correctAnswers);
                break;
            case WORD:
                question = new WordQuestion();
                ((WordQuestion) question).setAnswers(correctAnswers);
                break;
            case FACTORS_MULTIPLES:
                question = new FactorsMultiplesQuestion();
                ((FactorsMultiplesQuestion) question).setAnswer(correctAnswer);
                break;
            case PROBABILITY:
                question = new ProbabilityCalculationQuestion();
                ((ProbabilityCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case PROVE:
                question = new ProveQuestion();
                ((ProveQuestion) question).setAnswers(correctAnswers);
                break;
            case RATIO_PROPORTION:
                question = new RatioProportionQuestion();
                ((RatioProportionQuestion) question).setAnswer(correctAnswer);
                break;
            case STATISTICS:
                question = new StatisticsCalculationQuestion();
                ((StatisticsCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case UNIT_CONVERSION:
                question = new UnitConversionQuestion();
                ((UnitConversionQuestion) question).setAnswers(correctAnswers);
                break;
            case SHORT_ANSWER:
                question = new ShortAnswerQuestion();
                ((ShortAnswerQuestion) question).setAnswers(correctAnswers);
                break;
            default:
                logger.error("Failed to create simple problem.");
        }

        question.setSolutions(solutions);
        question.setPreferredSolution(preferredSolution);
        question.setQuestionIndex(1);
        question.setQuestionHypertext(questionDto.getQuestionHypertext());
        question.setDifficulty(questionDto.getDifficulty());
        question.setQuestionScore(questionDto.getQuestionScore());
        question.setNeedSteps(questionDto.isNeedSteps());

        question.setProblemType(problemType);
        question.setQuestionType(questionType);
        question.setProblemTypeId(problemType.getTypeId());
        question.setQuestionTypeId(questionType.getTypeId());
        /*if (Objects.nonNull(questionType)) {
            question.setHasMultipleAnswers(questionType.getAnswersQuantity() == 0);
            question.setHasOptions(questionType.isHasOption());
        }*/

        question.setAction(Actions.CREATE);
        return question;
    }

    private Question createByHybridQuestionDto(CreateQuestionDto questionDto, ProblemType problemType) {

        var questionType = questionTypeRepository.getQuestionType(questionDto.getQuestionTypeId());
        QuestionModes questionMode = null;
        if (questionType != null)
            questionMode = questionType.getQuestionMode();

        Question question = null;

        // pre process solutions
        var solutions = new ArrayList<Solution>();
        solutions.addAll(createBySolutionDtoList(questionDto.getSolutions()));
        Solution preferredSolution = null;
        for (var solution : solutions) {
            if (solution.isPreferred())
                preferredSolution = solution;
        }

        // 如果 questionDto hasOptions == true, 则无需传递answers
        Collection<Answer> correctAnswers = new ArrayList<>();
        Answer correctAnswer = null;
        var options = new ArrayList<Option>();
        if (questionDto.getOptions().size() > 0) {
            // 如果CreateSimpleCommand中包含了Options，则从选项中获取正确答案，忽略Command中的Answers
            // pre process options
            options.addAll(createByOptionDtoList(questionDto.getOptions()));
        } else {
            // pre process answers
            correctAnswers.addAll(createByAnswerDtoList(questionDto.getAnswers()));
            if (correctAnswers.size() == 1)
                correctAnswer = (Answer) correctAnswers.toArray()[0];
        }

        switch (questionMode) {
            case TRUE_FALSE:
                question = new TrueFalseQuestion();
                ((TrueFalseQuestion) question).setAnswer((BooleanAnswer) correctAnswer);
                break;
            case MULTIPLE_CHOICE_TWO_OPTIONS:
            case MULTIPLE_CHOICE_THREE_OPTIONS:
            case MULTIPLE_CHOICE_FOUR_OPTIONS:
            case MULTIPLE_CHOICE_FIVE_OPTIONS:
                question = new MultipleChoiceQuestion();
                ((MultipleChoiceQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case MULTIPLE_SELECTION_FOUR_OPTIONS:
            case MULTIPLE_SELECTION_FIVE_OPTIONS:
            case MULTIPLE_SELECTION_SIX_OPTIONS:
            case MULTIPLE_SELECTION_SEVEN_OPTIONS:
                question = new MultipleSelectionQuestion();
                ((MultipleSelectionQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case CALCULATION_NUMBER:
            case CALCULATION_EXPRESSION:
                question = new CalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case COMPLETION_DATETIME:
            case COMPLETION_HYBRID:
            case COMPLETION_LATEX:
            case COMPLETION_NUMBER:
            case COMPLETION_NUMBER_SERIES:
            case COMPLETION_OPERATOR:
            case COMPLETION_RANGE:
            case COMPLETION_SENTENCE:
            case COMPLETION_TEXT:
            case COMPLETION_UNIT:
            case COMPLETION_DECIMAL_RANGE:
                question = new CompletionQuestion();
                ((CompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case GEOMETRY_CALCULATION_ANGLE_DEGREE:
            case GEOMETRY_CALCULATION_AREA:
            case GEOMETRY_CALCULATION_EDGE_PERIMETER:
            case GEOMETRY_CALCULATION_VOLUME_CAPACITY:
                question = new GeometryCalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case GEOMETRY_COMPLETION_ANGLE_EDGE_RELATION:
            case GEOMETRY_COMPLETION_EDGE_ANGLE:
            case GEOMETRY_COMPLETION_POLYGON:
                question = new GeometryCompletionQuestion();
                ((GeometryCompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case COLUMN_CALCULATION_DIVISION:
            case COLUMN_CALCULATION_MINUS:
            case COLUMN_CALCULATION_PLUS:
            case COLUMN_CALCULATION_TIMES:
                question = new ColumnCalculationQuestion();
                ((ColumnCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case FORMULA_SOLVE_EQUATION:
            case FORMULA_SOLVE_INEQUALITY:
                question = new EquationInequalityQuestion();
                ((EquationInequalityQuestion) question).setAnswers(correctAnswers);
                break;
            case WORD:
                question = new WordQuestion();
                ((WordQuestion) question).setAnswers(correctAnswers);
                break;
            case FACTORS_MULTIPLES:
                question = new FactorsMultiplesQuestion();
                ((FactorsMultiplesQuestion) question).setAnswer(correctAnswer);
                break;
            case PROBABILITY_CALCULATION:
                question = new ProbabilityCalculationQuestion();
                ((ProbabilityCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case PROVE:
                question = new ProveQuestion();
                ((ProveQuestion) question).setAnswers(correctAnswers);
                break;
            case RATION_PROPORTION_PROPORTION:
            case RATION_PROPORTION_RATE:
            case RATION_PROPORTION_RATIO:
                question = new RatioProportionQuestion();
                ((RatioProportionQuestion) question).setAnswer(correctAnswer);
                break;
            case STATISTICS_AVERAGE:
            case STATISTICS_MEDIAN:
                question = new StatisticsCalculationQuestion();
                ((StatisticsCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case UNIT_CONVERSION_MEASURE:
            case UNIT_CONVERSION_MONEY:
                question = new UnitConversionQuestion();
                ((UnitConversionQuestion) question).setAnswers(correctAnswers);
                break;
            case SHORT_ANSWER:
                question = new ShortAnswerQuestion();
                ((ShortAnswerQuestion) question).setAnswers(correctAnswers);
                break;
            default:
                logger.error("Failed to create simple problem.");
        }
        question.getSolutions().addAll(solutions);
        question.setPreferredSolution(preferredSolution);
        question.setQuestionIndex(1);
        question.setQuestionHypertext(questionDto.getQuestionHypertext());
        question.setDifficulty(questionDto.getDifficulty());
        question.setNeedSteps(questionDto.isNeedSteps());
        question.setQuestionScore(questionDto.getQuestionScore());
        question.setProblemType(problemType);
        question.setQuestionType(questionType);
        question.setProblemTypeId(problemType.getTypeId());
        question.setQuestionTypeId(questionType.getTypeId());
        if (Objects.nonNull(questionType)) {
            //question.setHasMultipleAnswers(questionType.getAnswersQuantity() == 0);
            question.setHasOptions(questionType.isHasOption());
        }

        question.setAction(Actions.CREATE);
        return question;
    }

    private Question createByHybridUpdateQuestionDto(UpdateQuestionDto questionDto, ProblemType problemType) {

        var questionType = questionTypeRepository.getQuestionType(questionDto.getQuestionTypeId());
        QuestionModes questionMode = null;
        if (questionType != null)
            questionMode = questionType.getQuestionMode();

        Question question = null;

        // pre process solutions
        var solutions = new ArrayList<Solution>();
        solutions.addAll(createByUpdateSolutionDtoList(questionDto.getSolutions()));
        Solution preferredSolution = null;
        for (var solution : solutions) {
            if (solution.isPreferred())
                preferredSolution = solution;
        }

        // 如果 questionDto hasOptions == true, 则无需传递answers
        Collection<Answer> correctAnswers = new ArrayList<>();
        Answer correctAnswer = null;
        var options = new ArrayList<Option>();
        if (questionDto.getOptions().size() > 0) {
            // 如果CreateSimpleCommand中包含了Options，则从选项中获取正确答案，忽略Command中的Answers
            // pre process options
            options.addAll(createByUpdateOptionDtoList(questionDto.getOptions()));
        } else {
            // pre process answers
            correctAnswers.addAll(createByUpdateAnswerDtoList(questionDto.getAnswers()));
            if (correctAnswers.size() == 1)
                correctAnswer = (Answer) correctAnswers.toArray()[0];
        }

        switch (questionMode) {
            case TRUE_FALSE:
                question = new TrueFalseQuestion();
                ((TrueFalseQuestion) question).setAnswer((BooleanAnswer) correctAnswer);
                break;
            case MULTIPLE_CHOICE_TWO_OPTIONS:
            case MULTIPLE_CHOICE_THREE_OPTIONS:
            case MULTIPLE_CHOICE_FOUR_OPTIONS:
            case MULTIPLE_CHOICE_FIVE_OPTIONS:
                question = new MultipleChoiceQuestion();
                ((MultipleChoiceQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case MULTIPLE_SELECTION_FOUR_OPTIONS:
            case MULTIPLE_SELECTION_FIVE_OPTIONS:
            case MULTIPLE_SELECTION_SIX_OPTIONS:
            case MULTIPLE_SELECTION_SEVEN_OPTIONS:
                question = new MultipleSelectionQuestion();
                ((MultipleSelectionQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case CALCULATION_NUMBER:
            case CALCULATION_EXPRESSION:
                question = new CalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case COMPLETION_DATETIME:
            case COMPLETION_HYBRID:
            case COMPLETION_LATEX:
            case COMPLETION_NUMBER:
            case COMPLETION_NUMBER_SERIES:
            case COMPLETION_OPERATOR:
            case COMPLETION_RANGE:
            case COMPLETION_SENTENCE:
            case COMPLETION_TEXT:
            case COMPLETION_UNIT:
            case COMPLETION_DECIMAL_RANGE:
                question = new CompletionQuestion();
                ((CompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case GEOMETRY_CALCULATION_ANGLE_DEGREE:
            case GEOMETRY_CALCULATION_AREA:
            case GEOMETRY_CALCULATION_EDGE_PERIMETER:
            case GEOMETRY_CALCULATION_VOLUME_CAPACITY:
                question = new GeometryCalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case GEOMETRY_COMPLETION_ANGLE_EDGE_RELATION:
            case GEOMETRY_COMPLETION_EDGE_ANGLE:
            case GEOMETRY_COMPLETION_POLYGON:
                question = new GeometryCompletionQuestion();
                ((GeometryCompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case COLUMN_CALCULATION_DIVISION:
            case COLUMN_CALCULATION_MINUS:
            case COLUMN_CALCULATION_PLUS:
            case COLUMN_CALCULATION_TIMES:
                question = new ColumnCalculationQuestion();
                ((ColumnCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case FORMULA_SOLVE_EQUATION:
            case FORMULA_SOLVE_INEQUALITY:
                question = new EquationInequalityQuestion();
                ((EquationInequalityQuestion) question).setAnswers(correctAnswers);
                break;
            case WORD:
                question = new WordQuestion();
                ((WordQuestion) question).setAnswers(correctAnswers);
                break;
            case FACTORS_MULTIPLES:
                question = new FactorsMultiplesQuestion();
                ((FactorsMultiplesQuestion) question).setAnswer(correctAnswer);
                break;
            case PROBABILITY_CALCULATION:
                question = new ProbabilityCalculationQuestion();
                ((ProbabilityCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case PROVE:
                question = new ProveQuestion();
                ((ProveQuestion) question).setAnswers(correctAnswers);
                break;
            case RATION_PROPORTION_PROPORTION:
            case RATION_PROPORTION_RATE:
            case RATION_PROPORTION_RATIO:
                question = new RatioProportionQuestion();
                ((RatioProportionQuestion) question).setAnswer(correctAnswer);
                break;
            case STATISTICS_AVERAGE:
            case STATISTICS_MEDIAN:
                question = new StatisticsCalculationQuestion();
                ((StatisticsCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case UNIT_CONVERSION_MEASURE:
            case UNIT_CONVERSION_MONEY:
                question = new UnitConversionQuestion();
                ((UnitConversionQuestion) question).setAnswers(correctAnswers);
                break;
            case SHORT_ANSWER:
                question = new ShortAnswerQuestion();
                ((ShortAnswerQuestion) question).setAnswers(correctAnswers);
                break;
            default:
                logger.error("Failed to create simple problem.");
        }
        question.getSolutions().addAll(solutions);
        question.setPreferredSolution(preferredSolution);
        question.setQuestionIndex(1);
        question.setQuestionHypertext(questionDto.getQuestionHypertext());
        question.setDifficulty(questionDto.getDifficulty());
        question.setNeedSteps(questionDto.isNeedSteps());
        question.setQuestionScore(questionDto.getQuestionScore());
        question.setProblemType(problemType);
        question.setQuestionType(questionType);
        question.setProblemTypeId(problemType.getTypeId());
        question.setQuestionTypeId(questionType.getTypeId());
        if (Objects.nonNull(questionType)) {
            //question.setHasMultipleAnswers(questionType.getAnswersQuantity() == 0);
            question.setHasOptions(questionType.isHasOption());
        }

        question.setAction(Actions.CREATE);
        return question;
    }

    private Question createByUpdateQuestionDto(CommonQuestionModes commonQuestionMode, UpdateQuestionDto questionDto, ProblemType problemType, QuestionType questionType) {
        Question question = null;

        // pre process solutions
        var solutions = new ArrayList<Solution>();
        solutions.addAll(createByUpdateSolutionDtoList(questionDto.getSolutions()));
        Solution preferredSolution = null;
        for (var solution : solutions) {
            if (solution.isPreferred())
                preferredSolution = solution;
        }

        // 如果 questionDto hasOptions == true, 则无需传递answers
        Collection<Answer> correctAnswers = new ArrayList<>();
        Answer correctAnswer = null;
        var options = new ArrayList<Option>();
        if (questionDto.getOptions().size() > 0) {
            // 如果CreateSimpleCommand中包含了Options，则从选项中获取正确答案，忽略Command中的Answers
            // pre process options
            options.addAll(createByUpdateOptionDtoList(questionDto.getOptions()));
        } else {
            // pre process answers
            correctAnswers.addAll(createByUpdateAnswerDtoList(questionDto.getAnswers()));
            if (correctAnswers.size() == 1)
                correctAnswer = (Answer) correctAnswers.toArray()[0];
        }

        //var options = createByOptionDtoList(questionDto.getOptions());
        //var solutions = createBySolutionDtoList(questionDto.getSolutions());
        //var correctAnswers = createByAnswerDtoList(questionDto.getAnswers());
        //Answer correctAnswer = null;
        //if (correctAnswers.size() == 1)
        //    correctAnswer = (Answer) correctAnswers.toArray()[0];

        switch (commonQuestionMode) {
            case TRUE_FALSE:
                question = new TrueFalseQuestion();
                ((TrueFalseQuestion) question).setAnswer((BooleanAnswer) correctAnswer);
                break;
            case MULTIPLE_CHOICE:
                question = new MultipleChoiceQuestion();
                ((MultipleChoiceQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case MULTIPLE_SELECTION:
                question = new MultipleSelectionQuestion();
                ((MultipleSelectionQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case CALCULATION:
                question = new CalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case COMPLETION:
                question = new CompletionQuestion();
                ((CompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case GEOMETRY_CALCULATION:
                question = new GeometryCalculationQuestion();
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case GEOMETRY_COMPLETION:
                question = new GeometryCompletionQuestion();
                ((GeometryCompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case COLUMN_CALCULATION:
                question = new ColumnCalculationQuestion();
                ((ColumnCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case FORMULA_SOLVE:
                question = new EquationInequalityQuestion();
                ((EquationInequalityQuestion) question).setAnswers(correctAnswers);
                break;
            case WORD:
                question = new WordQuestion();
                ((WordQuestion) question).setAnswers(correctAnswers);
                break;
            case FACTORS_MULTIPLES:
                question = new FactorsMultiplesQuestion();
                ((FactorsMultiplesQuestion) question).setAnswer(correctAnswer);
                break;
            case PROBABILITY:
                question = new ProbabilityCalculationQuestion();
                ((ProbabilityCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case PROVE:
                question = new ProveQuestion();
                ((ProveQuestion) question).setAnswers(correctAnswers);
                break;
            case RATIO_PROPORTION:
                question = new RatioProportionQuestion();
                ((RatioProportionQuestion) question).setAnswer(correctAnswer);
                break;
            case STATISTICS:
                question = new StatisticsCalculationQuestion();
                ((StatisticsCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case UNIT_CONVERSION:
                question = new UnitConversionQuestion();
                ((UnitConversionQuestion) question).setAnswers(correctAnswers);
                break;
            case SHORT_ANSWER:
                question = new ShortAnswerQuestion();
                ((ShortAnswerQuestion) question).setAnswers(correctAnswers);
                break;
            default:
                logger.error("Failed to create simple problem.");
        }
        question.getSolutions().addAll(solutions);
        question.setPreferredSolution(preferredSolution);
        question.setQuestionIndex(1);
        question.setQuestionHypertext(questionDto.getQuestionHypertext());
        question.setDifficulty(questionDto.getDifficulty());
        question.setNeedSteps(questionDto.isNeedSteps());
        question.setQuestionScore(questionDto.getQuestionScore());
        question.setProblemType(problemType);
        question.setQuestionType(questionType);
        question.setProblemTypeId(problemType.getTypeId());
        question.setQuestionTypeId(questionType.getTypeId());
        /*if (Objects.nonNull(questionType)) {
            question.setHasMultipleAnswers(questionType.getAnswersQuantity() == 0);
            question.setHasOptions(questionType.isHasOption());
        }*/

        question.setAction(Actions.CREATE);
        return question;
    }

    private void deleteByUpdateQuestionDto(UpdateQuestionDto questionDto, Question question) {
        if (questionDto.getAction() == Actions.DELETE
                && question.getQuestionId() == questionDto.getQuestionId()) {
            question.setAction(Actions.DELETE);
        }
    }

    private void updateByUpdateQuestionDto(@NotNull UpdateQuestionDto questionDto, @NotNull Question question) {
        // SimpleProblem 问题仅允许修改
        if (question.getQuestionId() != questionDto.getQuestionId()) {
            logger.error("Failed to match the question: {} - {}", questionDto.getQuestionId(), question.getQuestionId());
            return;
        }

        // 修改问题属性
        question.setQuestionHypertext(questionDto.getQuestionHypertext());
        question.setDifficulty(questionDto.getDifficulty());
        question.setAction(Actions.UPDATE);

        var updatedSolutions = updateBySolutionDtoList(question.getSolutions(), questionDto.getSolutions());
        question.setSolutions(updatedSolutions);

        // 如果是单选或多选题， 不允许删除选项，仅仅允许修改部分或全部选项，仅仅选项内容超文本几是否正确答案可修改
        if (questionDto.getOptions().size() >= 1) {
            var updatedOptions = updateByOptionDtoList(question.getCurrentOptions(), questionDto.getOptions());
            // question.getCurrentOptions().clear();
            // question.getCurrentOptions().addAll(updatedOptions);

            Collection<Long> correctOptionIds = new ArrayList<>();
            for (var option : updatedOptions) {
                if (option.isCorrectAnswer())
                    correctOptionIds.add(option.getOptionId());
            }
            // 根据修改后的正确选项调整答案


            if (correctOptionIds.size() == 0) {
                logger.error("Cannot find a correct option answer.");
                return;
            }

            var updatedOptionAnswer = updateOptionAnswer(question.getCurrentAnswer(), correctOptionIds);
            question.getCurrentAnswers().clear();
            question.getCurrentAnswers().add(updatedOptionAnswer);

            if (Objects.isNull(question.getCurrentAnswer())) {
                logger.error("Cannot find a correct answer.");
                return;
            }
        } else {
            // 对于多答案的问题，有可能出现删除或新增、或修改现有答案值、序号、类型的情况
            var answerDtoList = questionDto.getAnswers();
            var updatedAnswers = updateByAnswerDtoList(question.getCurrentAnswers(), answerDtoList);
            question.getCurrentAnswers().clear();
            question.getCurrentAnswers().addAll(updatedAnswers);
        }
    }

    private Question createByUpdateQuestionDto(CommonQuestionModes commonQuestionMode, CompositeProblem compositeProblem, ProblemType problemType, QuestionType questionType, UpdateQuestionDto questionDto) {
        var solutions = new ArrayList<Solution>();
        Solution preferredSolution = null;
        if (!CollectionUtils.isEmpty(questionDto.getSolutions())) {
            for (var solutionDto : questionDto.getSolutions()) {
                var solution = new Solution();
                solution.setSolutionHypertext(solutionDto.getSolutionHypertext());
                solution.setSolutionIndex(solutionDto.getSolutionIndex());
                solution.setPreferred(solutionDto.isPreferred());
                solution.setAction(Actions.CREATE);
                solutions.add(solution);
                if (solution.isPreferred())
                    preferredSolution = solution;
            }
        } else {
            // 强制建立空解题思路
            var solution = new Solution();
            solution.setSolutionHypertext("");
            solution.setSolutionIndex(1);
            solution.setAction(Actions.CREATE);
            solution.setPreferred(true);
            solutions.add(solution);
            preferredSolution = solution;
        }

        // 如果 questionDto hasOptions == true, 则无需传递answers
        Collection<Answer> correctAnswers = new ArrayList<>();
        Answer correctAnswer = null;

        var options = new ArrayList<Option>();
        if (questionDto.getOptions().size() > 0) {
            for (var optionDto : questionDto.getOptions()) {
                var option = new Option();
                option.setCorrectAnswer(optionDto.isCorrectAnswer());
                option.setOptionHypertext(optionDto.getOptionHypertext());
                option.setOptionIndex(optionDto.getOptionIndex());
                option.setAction(Actions.CREATE);
                options.add(option);
            }
        } else {
            CreateAnswerDto firstAnswerDto = null;
            if (questionDto.getAnswers().size() == 1) {
                firstAnswerDto = (CreateAnswerDto) questionDto.getAnswers().toArray()[0];
                correctAnswer = createAnswerByType(AnswerTypes.valueOf(firstAnswerDto.getAnswerTypeId()), firstAnswerDto.getAnswerIndex(), firstAnswerDto.getAnswerHypertext());
                correctAnswer.setAction(Actions.CREATE);
            } else if (questionDto.getAnswers().size() > 1) {
                for (var answerDto : questionDto.getAnswers()) {
                    var answer = createAnswerByType(AnswerTypes.valueOf(answerDto.getAnswerTypeId()), answerDto.getAnswerIndex(), answerDto.getAnswerHypertext());
                    answer.setAction(Actions.CREATE);
                    correctAnswers.add(answer);
                }
            }
        }

        Question question = null;
        switch (commonQuestionMode) {
            case TRUE_FALSE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeTrueFalseProblem();
                question = new TrueFalseQuestion();
                ((CompositeTrueFalseProblem) compositeProblem).getQuestions().add((TrueFalseQuestion) question);
                ((TrueFalseQuestion) question).setAnswer((BooleanAnswer) correctAnswer);
                break;
            case MULTIPLE_CHOICE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeMultipleChoiceProblem();
                question = new MultipleChoiceQuestion();
                ((CompositeMultipleChoiceProblem) compositeProblem).getQuestions().add((MultipleChoiceQuestion) question);
                ((MultipleChoiceQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case MULTIPLE_SELECTION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeMultipleSelectionProblem();
                question = new MultipleSelectionQuestion();
                ((CompositeMultipleSelectionProblem) compositeProblem).getQuestions().add((MultipleSelectionQuestion) question);
                ((MultipleSelectionQuestion) question).setOptions(options);
                ((MultipleChoiceQuestion) question).setAnswer(null);
                break;
            case CALCULATION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeCalculationProblem();
                question = new CalculationQuestion();
                ((CompositeCalculationProblem) compositeProblem).getQuestions().add((CalculationQuestion) question);
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case COMPLETION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeCompletionProblem();
                question = new CompletionQuestion();
                ((CompositeCompletionProblem) compositeProblem).getQuestions().add((CompletionQuestion) question);
                ((CompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case GEOMETRY_CALCULATION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeGeometryCalculationProblem();
                question = new GeometryCalculationQuestion();
                ((CompositeGeometryCalculationProblem) compositeProblem).getQuestions().add((GeometryCalculationQuestion) question);
                ((CalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case GEOMETRY_COMPLETION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeGeometryCompletionProblem();
                question = new GeometryCompletionQuestion();
                ((CompositeGeometryCompletionProblem) compositeProblem).getQuestions().add((GeometryCompletionQuestion) question);
                ((GeometryCompletionQuestion) question).setAnswers(correctAnswers);
                break;
            case COLUMN_CALCULATION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeColumnCalculationProblem();
                question = new ColumnCalculationQuestion();
                ((CompositeColumnCalculationProblem) compositeProblem).getQuestions().add((ColumnCalculationQuestion) question);
                ((ColumnCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case FORMULA_SOLVE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeEquationInequalityProblem();
                question = new EquationInequalityQuestion();
                ((CompositeEquationInequalityProblem) compositeProblem).getQuestions().add((EquationInequalityQuestion) question);
                ((EquationInequalityQuestion) question).setAnswers(correctAnswers);
                break;
            case WORD:
                if (compositeProblem == null)
                    compositeProblem = new CompositeWordProblem();
                question = new WordQuestion();
                ((CompositeWordProblem) compositeProblem).getQuestions().add((WordQuestion) question);
                ((WordQuestion) question).setAnswers(correctAnswers);
                break;
            case FACTORS_MULTIPLES:
                if (compositeProblem == null)
                    compositeProblem = new CompositeFactorsMultiplesProblem();
                question = new FactorsMultiplesQuestion();
                ((CompositeFactorsMultiplesProblem) compositeProblem).getQuestions().add((FactorsMultiplesQuestion) question);
                ((FactorsMultiplesQuestion) question).setAnswer(correctAnswer);
                break;
            case PROBABILITY:
                if (compositeProblem == null)
                    compositeProblem = new CompositeProbabilityProblem();
                question = new ProbabilityCalculationQuestion();
                ((CompositeProbabilityProblem) compositeProblem).getQuestions().add((ProbabilityCalculationQuestion) question);
                ((ProbabilityCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case PROVE:
                if (compositeProblem == null)
                    compositeProblem = new CompositeProveProblem();
                question = new ProveQuestion();
                ((CompositeProveProblem) compositeProblem).getQuestions().add((ProveQuestion) question);
                ((ProveQuestion) question).setAnswers(correctAnswers);
                break;
            case RATIO_PROPORTION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeRatioProportionProblem();
                question = new RatioProportionQuestion();
                ((CompositeRatioProportionProblem) compositeProblem).getQuestions().add((RatioProportionQuestion) question);
                ((RatioProportionQuestion) question).setAnswer(correctAnswer);
                break;
            case STATISTICS:
                if (compositeProblem == null)
                    compositeProblem = new CompositeStatisticsProblem();
                question = new StatisticsCalculationQuestion();
                ((CompositeStatisticsProblem) compositeProblem).getQuestions().add((StatisticsCalculationQuestion) question);
                ((StatisticsCalculationQuestion) question).setAnswer(correctAnswer);
                break;
            case UNIT_CONVERSION:
                if (compositeProblem == null)
                    compositeProblem = new CompositeUnitConversionProblem();
                question = new UnitConversionQuestion();
                ((CompositeUnitConversionProblem) compositeProblem).getQuestions().add((UnitConversionQuestion) question);
                ((UnitConversionQuestion) question).setAnswers(correctAnswers);
                break;
            case SHORT_ANSWER:
                if (compositeProblem == null)
                    compositeProblem = new CompositeShortAnswerProblem();
                question = new ShortAnswerQuestion();
                ((CompositeShortAnswerProblem) compositeProblem).getQuestions().add((ShortAnswerQuestion) question);
                ((ShortAnswerQuestion) question).setAnswers(correctAnswers);
                break;
            default:
                logger.error("Failed to create simple problem.");
        }

        question.setQuestionIndex(1);
        question.setProblemType(problemType);
        question.setQuestionType(questionType);
        question.setProblemTypeId(problemType.getTypeId());
        question.setQuestionTypeId(questionType.getTypeId());
        question.setQuestionHypertext(questionDto.getQuestionHypertext());
        question.setDifficulty(questionDto.getDifficulty());
        if (Objects.nonNull(questionType)) {
            //question.setHasMultipleAnswers(questionType.getAnswersQuantity() == 0);
            question.setHasOptions(questionType.isHasOption());
        }
        question.setNeedSteps(questionDto.isNeedSteps());
        question.getSolutions().addAll(solutions);
        question.setPreferredSolution(preferredSolution);
        question.setAction(Actions.CREATE);

        return question;
    }

    //endregion

    // region  solution dto
    private Collection<Solution> createBySolutionDtoList(Collection<CreateSolutionDto> solutionDtoList) {
        var solutions = new ArrayList<Solution>();
        if (!CollectionUtils.isEmpty(solutionDtoList)) {
            for (var solutionDto : solutionDtoList) {
                var solution = new Solution();
                solution.setSolutionHypertext(solutionDto.getSolutionHypertext());
                solution.setSolutionIndex(solutionDto.getSolutionIndex());
                solution.setPreferred(solutionDto.isPreferred());
                solution.setAction(Actions.CREATE);
                solutions.add(solution);
            }
        } else {
            // 强制建立空解题思路
            var solution = new Solution();
            solution.setSolutionHypertext("");
            solution.setSolutionIndex(1);
            solution.setPreferred(true);
            solution.setAction(Actions.CREATE);
            solutions.add(solution);
        }

        return solutions;
    }

    private Collection<Solution> createByUpdateSolutionDtoList(Collection<UpdateSolutionDto> solutionDtoList) {
        var solutions = new ArrayList<Solution>();
        if (CollectionUtils.isEmpty(solutionDtoList)) {
            for (var solutionDto : solutionDtoList) {
                var solution = new Solution();
                solution.setSolutionHypertext(solutionDto.getSolutionHypertext());
                solution.setSolutionIndex(solutionDto.getSolutionIndex());
                solution.setPreferred(solutionDto.isPreferred());
                solution.setAction(Actions.CREATE);
                solutions.add(solution);
            }
        } else {
            // 强制建立空解题思路
            var solution = new Solution();
            solution.setSolutionHypertext("");
            solution.setSolutionIndex(1);
            solution.setPreferred(true);
            solution.setAction(Actions.CREATE);
            solutions.add(solution);
        }

        return solutions;
    }

    private Collection<Solution> updateBySolutionDtoList(Collection<Solution> solutions, Collection<UpdateSolutionDto> solutionDtoList) {
        // 更新Solution
        for (var solutionDto : solutionDtoList) {
            if (solutionDto.getAction() == Actions.DELETE) {
                for (var solution : solutions) {
                    if (solution.getSolutionId() == solutionDto.getSolutionId()) {
                        solution.setAction(Actions.DELETE);
                    }
                }
            } else if (solutionDto.getAction() == Actions.UPDATE) {
                for (var solution : solutions) {
                    if (solution.getSolutionId() == solutionDto.getSolutionId()) {
                        solution.setSolutionIndex(solutionDto.getSolutionIndex());
                        solution.setSolutionHypertext(solutionDto.getSolutionHypertext());
                        solution.setPreferred(solutionDto.isPreferred());
                        solution.setAction(Actions.UPDATE);
                    }
                }
            } else if (solutionDto.getAction() == Actions.CREATE) {
                var solution = new Solution();
                solution.setSolutionIndex(solutionDto.getSolutionIndex());
                solution.setSolutionHypertext(solutionDto.getSolutionHypertext());
                solution.setPreferred(solutionDto.isPreferred());
                solution.setAction(Actions.CREATE);
                solutions.add(solution);
            }
        }
        return solutions;
    }


    // endregion

    // region  answer dto
    private Answer updateOptionAnswer(Answer answer, Collection<Long> correctOptionIds) {
        if (answer instanceof MultipleOptionAnswer) {
            //if (correctOptionIds.size() > 1) {
            var multipleOptionAnswer = (MultipleOptionAnswer) answer;
            var correctOptions = correctOptionIds.stream().sorted().collect(Collectors.toList());
            var valueText = StringUtils.join(correctOptions, ",");
            multipleOptionAnswer.setValues(correctOptions);
            multipleOptionAnswer.setAnswerOptionId(0);
            multipleOptionAnswer.setAnswerHypertext(valueText);
            multipleOptionAnswer.setAction(Actions.UPDATE);
        } else {
            var optionAnswer = (OptionAnswer) answer;
            var correctOptionId = (Long) correctOptionIds.toArray()[0];
            optionAnswer.setValue(correctOptionId);
            optionAnswer.setPrefix("");
            optionAnswer.setAnswerOptionId(correctOptionId);
            optionAnswer.setAnswerHypertext(String.valueOf(correctOptionId));
            optionAnswer.setAction(Actions.UPDATE);
        }
        return answer;
    }

    private Answer createAnswerByType(AnswerTypes answerTypes, int index, String content) {
        switch (answerTypes) {
            // 对于单选多选题，无需传递Answer， Answer通过Options中 isCorrectAnswer 创建
            //case OPTION:
            //    return new OptionAnswer(0, 0, index, 0, Long.valueOf(correctOptionIndex));
            //case MULTIPLE_OPTION:
            //    return new MultipleOptionAnswer(0, 0, index, 0, ParseHelper.parseLong(content, ","));
            case BOOLEAN:
                return new BooleanAnswer(0, 0, index, 0, new LatexBoolean(content));
            case INTEGER:
                return new IntegerAnswer(0, 0, index, 0, new LatexInteger(content));
            case INTEGER_RANGE:
                return new IntegerRangeAnswer(0, 0, index, 0, new LatexIntegerRange(content));
            case INTEGER_SERIES:
                return new IntegerSeriesAnswer(0, 0, index, 0, new LatexIntegerSeries(ParseHelper.parseBigInteger(content, ",")));
            case INTEGER_SERIES_SORTED:
                return new SortedIntegerSeriesAnswer(0, 0, index, 0, new LatexIntegerSeries(ParseHelper.parseBigInteger(content, ",")));
            case INEQUALITY_SOLUTION:
                return new InequalitySolutionAnswer(0, 0, index, 0, LatexInequalitySolution.parseInequalitySolution(content));
            case ARITHMETIC_OPERATOR:
                return new OperatorAnswer(0, 0, index, 0, new LatexOperator(content), AnswerTypes.ARITHMETIC_OPERATOR);
            case COMPARE_OPERATOR:
                return new OperatorAnswer(0, 0, index, 0, new LatexOperator(content), AnswerTypes.COMPARE_OPERATOR);
            case ARITHMETIC_EXPRESSION:
                return new ExpressionAnswer(0, 0, index, 0, new LatexArithmeticExpression(content));
            case ARITHMETIC_EQUATION:
                return new EquationAnswer(0, 0, index, 0, new LatexArithmeticEquation(content));
            case ARITHMETIC_INEQUALITY:
                return new InequalityAnswer(0, 0, index, 0, new LatexArithmeticInequality(content));
            case GEOMETRY_ANGLE_DENOTE:
                return new AngleDenoteAnswer(0, 0, index, 0, new LatexAngleDenote(content));
            case GEOMETRY_EDGE_DENOTE:
                return new EdgeDenoteAnswer(0, 0, index, 0, new LatexEdgeDenote(content));
            case GEOMETRY_PENTAGON_DENOTE:
                return new PentagonDenoteAnswer(0, 0, index, 0, new LatexPentagonDenote(content));
            case GEOMETRY_POINT_DENOTE:
                return new PointDenoteAnswer(0, 0, index, 0, new LatexPointDenote(content));
            case GEOMETRY_VERTEX_DENOTE:
                return new VertexDenoteAnswer(0, 0, index, 0, new LatexVertexDenote(content));
            case GEOMETRY_XY_POINT_DENOTE:
                return new XYPointDenoteAnswer(0, 0, index, 0, new LatexXYPointDenote(content));
            case GEOMETRY_XYZ_POINT_DENOTE:
                return new XYZPointDenoteAnswer(0, 0, index, 0, new LatexXYZPointDenote(content));
            case GEOMETRY_QUADRILATERAL_DENOTE:
                return new QuadrangleDenoteAnswer(0, 0, index, 0, new LatexQuadrangleDenote(content));
            case GEOMETRY_TRIANGLE_DENOTE:
                return new TriangleDenoteAnswer(0, 0, index, 0, new LatexTriangleDenote(content));
            case GEOMETRY_ANGLE_DEGREE:
                return new AngleDegreeAnswer(0, 0, index, 0, new LatexAngleDegree(content));
            case GEOMETRY_ANGLE_EDGE_RELATION:
            case TEXT:
                return new TextAnswer(0, 0, index, 0, content);
            case DATE:
                return new DateAnswer(0, 0, index, 0, new LatexDate(content));
            case DATE_TIME:
                return new DateTimeAnswer(0, 0, index, 0, new LatexDateTime(content));
            case TIME:
                return new TimeAnswer(0, 0, index, 0, new LatexTime(content));
            case DECIMAL:
                return new DecimalAnswer(0, 0, index, 0, new LatexDecimal(content));
            case DECIMAL_RANGE:
                return new DecimalRangeAnswer(0, 0, index, 0, new LatexDecimalRange(content));
            case DECIMAL_SERIES:
                return new DecimalSeriesAnswer(0, 0, index, 0, new LatexDecimalSeries(content));
            case DECIMAL_SERIES_SORTED:
                return new SortedDecimalSeriesAnswer(0, 0, index, 0, new LatexDecimalSeries(content));
            case EQUATION_SOLUTION:
                return new EquationSolutionAnswer(0, 0, index, 0, LatexEquationSolution.parseEquationSolution(content));
            case FRACTION:
                return new FractionAnswer(0, 0, index, 0, FractionUtils.toFraction(content));
            case LATEX:
                return new LatexAnswer(0, 0, index, 0, new LatexText(content, LatexTextEnum.GENERAL));
            case LOOP_DECIMAL_NUMBER:
                return new LoopDecimalAnswer(0, 0, index, 0, new LatexLoopDecimal(content));
            case MEASURE_UNIT_AREA:
                return new MeasureUnitAnswer(0, 0, index, 0, new LatexMeasureUnit(content), AnswerTypes.MEASURE_UNIT_AREA);
            case MEASURE_UNIT_CAPACITY:
                return new MeasureUnitAnswer(0, 0, index, 0, new LatexMeasureUnit(content), AnswerTypes.MEASURE_UNIT_CAPACITY);
            case MEASURE_UNIT_LENGTH:
                return new MeasureUnitAnswer(0, 0, index, 0, new LatexMeasureUnit(content), AnswerTypes.MEASURE_UNIT_LENGTH);
            case MEASURE_UNIT_VOLUME:
                return new MeasureUnitAnswer(0, 0, index, 0, new LatexMeasureUnit(content), AnswerTypes.MEASURE_UNIT_VOLUME);
            case MEASURE_UNIT_WEIGHT:
                return new MeasureUnitAnswer(0, 0, index, 0, new LatexMeasureUnit(content), AnswerTypes.MEASURE_UNIT_WEIGHT);
            case MONEY_RMB:
                return new MoneyUnitAnswer(0, 0, index, 0, new LatexMoneyUnit(content));
            case QUOTIENT_REMINDER:
                return new QuotientReminderAnswer(0, 0, index, 0, new LatexQuotientReminder(content));
            case RADICAL_NUMBER:
                return new RadicalNumberAnswer(0, 0, index, 0, RadicalNumberUtils.toRadicalNumber(content));
            case PROBABILITY:
                return new ProbabilityAnswer(0, 0, index, 0, new LatexDecimal(content));
            case RATE:
                return new RateAnswer(0, 0, index, 0, new LatexDecimal(content));
            case RATIO:
                return new RatioAnswer(0, 0, index, 0, new LatexRatio(content));
            case PROPORTION:
                return new ProportionAnswer(0, 0, index, 0, new LatexProportion(content));
            case PERCENT:
                return new PercentAnswer(0, 0, index, 0, new LatexPercent(content));
            case SCIENCE_NOTATION:
                return new ScienceNotationAnswer(0, 0, index, 0, new LatexScienceNotation(content));
            default:
                logger.error("Failed to convert the answer by type.");
                return null;
        }
    }

    private Collection<Answer> createByAnswerDtoList(Collection<CreateAnswerDto> answerDtoList) {
        var answers = new ArrayList<Answer>();
        for (var answerDto : answerDtoList) {
            var answer = createAnswerByType(AnswerTypes.valueOf(answerDto.getAnswerTypeId()), answerDto.getAnswerIndex(), answerDto.getAnswerHypertext());
            answer.setAnswerHypertext(answerDto.getAnswerHypertext());
            answer.setSolutionUrl(answerDto.getSolutionUrl());
            answer.setAction(Actions.CREATE);
            answers.add(answer);
        }
        return answers;
    }

    private Collection<Answer> createByUpdateAnswerDtoList(Collection<UpdateAnswerDto> answerDtoList) {
        var answers = new ArrayList<Answer>();
        for (var answerDto : answerDtoList) {
            var answer = createAnswerByType(AnswerTypes.valueOf(answerDto.getAnswerTypeId()), answerDto.getAnswerIndex(), answerDto.getAnswerHypertext());
            answer.setAnswerHypertext(answerDto.getAnswerHypertext());
            answer.setSolutionUrl(answerDto.getSolutionUrl());
            answer.setAction(Actions.CREATE);
            answers.add(answer);
        }
        return answers;
    }

    private Collection<Answer> updateByAnswerDtoList(Collection<Answer> answers, Collection<UpdateAnswerDto> updateAnswerDtoList) {
        // 答案允许删除和新增和修改
        for (var answerDto : updateAnswerDtoList) {
            if (answerDto.getAction() == Actions.CREATE) {
                var answerTypeEnum = AnswerTypes.valueOf(answerDto.getAnswerTypeId());
                var answer = createAnswerByType(answerTypeEnum, answerDto.getAnswerIndex(), answerDto.getAnswerHypertext());
                answer.setSolutionUrl(answerDto.getSolutionUrl());
                answer.setAction(Actions.CREATE);
                answers.add(answer);
            } else if (answerDto.getAction() == Actions.DELETE) {
                for (var answer : answers) {
                    if (answer.getAnswerId() == answerDto.getAnswerId()) {
                        answer.setAction(Actions.DELETE);
                    }
                }
            } else if (answerDto.getAction() == Actions.UPDATE) {
                for (var answer : answers) {
                    if (answer.getAnswerId() == answerDto.getAnswerId()) {
                        answer.setAnswerHypertext(answerDto.getAnswerHypertext());
                        answer.setAnswerIndex(answerDto.getAnswerIndex());
                        answer.setSolutionUrl(answerDto.getSolutionUrl());
                        answer.setAction(Actions.UPDATE);
                    }
                }
            }
        }
        return answers;
    }

    // endregion

    // region option dto
    private Collection<Option> createByOptionDtoList(Collection<CreateOptionDto> optionDtoList) {
        var options = new ArrayList<Option>();
        for (var optionDto : optionDtoList) {
            var option = new Option();
            option.setCorrectAnswer(optionDto.isCorrectAnswer());
            option.setOptionHypertext(optionDto.getOptionHypertext());
            option.setOptionIndex(optionDto.getOptionIndex());
            option.setAction(Actions.CREATE);
            options.add(option);
        }
        return options;
    }

    private Collection<Option> createByUpdateOptionDtoList(Collection<UpdateOptionDto> optionDtoList) {
        var options = new ArrayList<Option>();
        for (var optionDto : optionDtoList) {
            var option = new Option();
            option.setCorrectAnswer(optionDto.isCorrectAnswer());
            option.setOptionHypertext(optionDto.getOptionHypertext());
            option.setOptionIndex(optionDto.getOptionIndex());
            option.setAction(Actions.CREATE);
            options.add(option);
        }
        return options;
    }

    private Collection<Option> updateByOptionDtoList(Collection<Option> options, Collection<UpdateOptionDto> updateOptionDtoList) {
        // 选项不允许删除和新增，仅允许修改
        for (var optionDto : updateOptionDtoList) {
            for (var option : options) {
                if (optionDto.getOptionId() == option.getOptionId()) {
                    option.setOptionIndex(optionDto.getOptionIndex());
                    option.setOptionHypertext(optionDto.getOptionHypertext());
                    option.setCorrectAnswer(optionDto.isCorrectAnswer());
                    option.setAction(Actions.UPDATE);
                }
            }
        }
        return options;
    }

    // endregion
}
